package org.dlsu.mt.parser.generation;
import java.util.Vector;

public class GrammarList
{
	Vector<Grammar> list;
	
	public GrammarList()
	{
		list = new Vector();
	}
	
	public void addItem(Grammar g)
	{
		list.addElement(g);
	}
	
	public void addItem(String left, String right)
	{
		Grammar g = new Grammar(right, left);
		list.addElement(g);
	}
	
	public Grammar getRule(int index)
	{
		return list.get(index);
	}
	
	public int getNumRules()
	{
		return list.size();
	}
	
	public Vector<Grammar> getRules(String left)
	{
		Vector<Grammar> list = new Vector();
		
		for(int i = 0; i<this.list.size(); i++)
		{
			if(this.list.get(i).getLeft().equals(left))
			{
				list.addElement(this.list.get(i));
			}
		}
		if(!list.isEmpty())
			return list;
		else
			return null;
	}
	
	public int compare(String left, String sym1, String sym2)
	{
		Vector<Grammar> rules = getRules(left);
		
		if(rules.size() == 1)
		{
			Grammar g = rules.firstElement();
			return g.compare(sym1, sym2);
		}
		else
		{
			int temp = -1;
			for(int i=0;i<rules.size();i++)
			{
				Grammar g = rules.get(i);
				int val = g.compare(sym1, sym2);
				if(val == 1 || val == 2)
					return val;
				else if(val == 3)
				{
					temp = val;
				}
				else if(temp == -1 && val == 0)
				{
					temp = 0;
				}
			}
			if(temp != -1)
				return temp;
			else
				return 0;
		}
	}
	
	public Vector<String> order(Vector<String> symbolList, String start)
	{
		//String start is LFG Annotations
		Vector<String> testSymbols = null;
		
		//"2".out.println("order " + start);
		//for(int i=0;i<symbolList.size();i++)
		//	System.out.println(symbolList.get(i));
		//System.out.println();
		if(start.equals("root"))
		{
			testSymbols = new Vector();
			testSymbols.add("IC");
		}
		else
			testSymbols = getAssociatedNTSymbol(start);
		Vector<String> orderedList = null;
		boolean allFound = false;
		int i=0;
		while((i<testSymbols.size())&&!allFound)
		{
			orderedList = orderNT(symbolList, testSymbols.get(i));
			if(orderedList != null && orderedList.size() == symbolList.size())
				allFound = true;
			i++;
		}
		//if(orderedList != null)
		//{
			//System.out.println("finish ordering " + start + " with");
			//for(int z=0;z<orderedList.size();z++)
			//	System.out.println(orderedList.get(z));
			//System.out.println();
		//}
		//else
			//System.out.println("ordering " + start + " not successful");
		return orderedList;
	}
	
	public Vector<String> orderNT(Vector<String> symbolList, String start)
	{
		//System.out.println("orderNT " + start);
		//for(int i=0;i<symbolList.size();i++)
		//	System.out.println(symbolList.get(i));
		Vector<String> orderedList = null;
		boolean allFound = false;
		Vector<String> match = null;
		Vector<Grammar> gramList = getRules(start);
		
		if(gramList != null)
			gramList = orderGrammar(gramList, symbolList);
		//else
			//System.out.println(start + " has no rules");
		int x=0;
		

		while(x<gramList.size()&&!allFound)
		{
			Grammar g = gramList.get(x);
			Vector<String> tempList = g.getAnnotations();
			//System.out.println("annotations for " + g.getLeft());
			//for(int i=0;i<tempList.size();i++)
				//System.out.println(tempList.get(i));
			if(ratioMatch(symbolList, tempList) == 1.0)
			{
				//System.out.println("order all match");
				orderedList = new Vector();
				for(int z=0;z<tempList.size();z++)
				{
					if(foundInList(tempList.get(z), symbolList))
					{
						orderedList.add(tempList.get(z));
					}
				}
				allFound = true;
			}
			else
			{
				match = matches(symbolList, tempList);
				Vector<GrammarOrderItem> matchList = new Vector();
				
				if(!match.isEmpty())
				{
					match = orderNT(match, start);
					for(int w=0;w<match.size();w++)
						matchList.add(new GrammarOrderItem(match.get(w),"main"));					
				}
					
					
				Vector<String> nonmatch = nonmatch(symbolList, match);
				tempList = orderAnnotations(tempList, nonmatch);
				int a=0;
				while(a<tempList.size()&&!allFound)
				{
					if(tempList.get(a).charAt(0) == '!')
					{
						String temp = tempList.get(a);
						temp = temp.substring(1);
						Vector<String> result = orderNT(nonmatch, temp);
						if(!result.isEmpty())
						{
							int y=0;
							boolean found=false;
							while(y<matchList.size()&&!found)
							{
								String comp = null;
								if(matchList.get(y).getRule().equals("main"))
									comp = matchList.get(y).getSymbol();
								else
									comp = matchList.get(y).getRule();
								if(g.compare(comp,temp) == 2)
									found = true;
								else
									y++;
							}
							for(int q=result.size()-1;q>=0;q--)
							{
								matchList.add(y,new GrammarOrderItem(result.get(q),temp));
							}
							match = new Vector();
							for(int w=0;w<matchList.size();w++)
								match.add(matchList.get(w).getSymbol());
							nonmatch = nonmatch(symbolList, match);
							
							if(nonmatch.size() == 0)
							{
								allFound = true;
								orderedList = match;
							}
							else
							{
								//System.out.println("unmatched are");
								//for(int i=0;i<nonmatch.size();i++)
								//	System.out.println(nonmatch.get(i));
							}
						}
					}
					a++;
				}
			}
			if(!allFound)
			{
				if(orderedList == null)
					orderedList = match;
				else
				{
					if(orderedList.size()<match.size())
						orderedList = match;
				}
			}
			x++;
		}
		
		//if(orderedList != null)
		//{
		//	System.out.println("finish orderingNT " + start + " with");
		//	for(int z=0;z<orderedList.size();z++)
		//		System.out.println(orderedList.get(z));
		//	System.out.println();
		//}
		//else
		//	System.out.println("orderingNT " + start + " not successful");
		
		return orderedList;
	}
	
	public Vector<String> orderAnnotations(Vector<String> annotList, Vector<String> symbols)
	{
		for(int i=0;i<annotList.size();i++)
			if(annotList.get(i).charAt(0) != '!')
			{
				annotList.remove(i);
				i--;
			}
		Vector<Float> ratio = new Vector();
		
		for(int i=0;i<annotList.size();i++)
			ratio.add(new Float(getRatioFound(annotList.get(i), symbols)));
		
		Vector<String> temp = new Vector();	
		while(!annotList.isEmpty())
		{
			int index = getHighest(ratio);
			if(index != -1)
			{
				temp.add(annotList.get(index));
				annotList.remove(index);
				ratio.remove(index);
			}
			else
			{
				annotList.removeAllElements();
			}
		}
		return temp;
	}
	
	
	public Vector<String> getAssociatedNTSymbol(String name)
	{
		Vector<String> tempList = new Vector();
		Vector<Grammar> grammarList = getRulesContaining(name);
		for(int i=0;i<grammarList.size();i++)
		{
			Grammar g = grammarList.get(i);
			tempList.add(g.getSymbol(g.findPos(name)-2));
		}
		return tempList;
	}
	
	public Vector<Grammar> getRulesContaining(String name)
	{
		Vector<Grammar> tempList = new Vector();
		for(int i=0;i<list.size();i++)
		{
			if(list.get(i).isFound(name))
			{
				tempList.add(list.get(i));
			}
		}
		return tempList;
	}
	
	public float ratioMatch(Vector<String> list, Vector<String> grammar)
	{
		int count=0;
		for(int i=0;i<list.size();i++)
		{
			int x=0;
			boolean found=false;
			while(x<grammar.size()&&!found)
			{
				if(list.get(i).equals(grammar.get(x)))
				{
					count++;
					found = true;	
				}
				x++;
			}
		}
		return (float)1.0*count/list.size();
	}
	
	public Vector<String> matches(Vector<String> list, Vector<String> grammar)
	{
		Vector<String> match = new Vector();
		for(int i=0;i<list.size();i++)
		{
			int x=0;
			boolean found=false;
			while(x<grammar.size()&&!found)
			{
				if(list.get(i).equals(grammar.get(x)))
				{
					match.add(list.get(i));
					found = true;	
				}
				x++;
			}
		}
		return match;
	}
	
	public Vector<String> nonmatch(Vector<String> list, Vector<String> list2)
	{
		Vector<String> nonmatch = new Vector();
		for(int i=0;i<list.size();i++)
		{
			int x=0;
			boolean found=false;
			while(x<list2.size()&&!found)
			{
				if(list.get(i).equals(list2.get(x)))
				{
					found = true;	
				}
				x++;
			}
			if(!found)
			{
				nonmatch.add(list.get(i));
			}
		}
		return nonmatch;
	}
	
	public boolean foundInList(String text, Vector<String> list)
	{
		for(int i=0;i<list.size();i++)
		{
			if(list.get(i).equals(text))
				return true;
		}
		return false;
	}
	
	public Vector<Grammar> orderGrammar(Vector<Grammar> rules, Vector<String> symbols)
	{
		if(rules!= null)
		{
			Vector<Grammar> temp = new Vector();
			Vector<Float> ratio = new Vector();
			for(int i=0;i<rules.size();i++)
			{
				ratio.add(new Float(rules.get(i).getRatioFound(symbols)));
			}
			while(!rules.isEmpty())
			{
				int index = getHighest(ratio);
				if(index != -1)
				{
					temp.add(rules.get(index));
					rules.remove(index);
					ratio.remove(index);
				}
				else
				{
					rules.removeAllElements();
				}
			}
			return temp;
		}
		return null;
	}
	
	public float getRatioFound(String left, Vector<String> symbols)
	{
		Vector<Grammar> gramList = getRules(left);
		float high = 0;
		
		if(gramList!=null)
			for(int i=0;i<gramList.size();i++)
			{
				if(i == 0)
					high = gramList.get(i).getRatioFound(symbols);
				else
				{
					float temp = gramList.get(i).getRatioFound(symbols);
					if(temp>high)
						high = temp;
				}
			}
		
		return high;
	}
	
	public int getHighest(Vector<Float> values)
	{
		float high=-1;
		int index=-1;
		for(int i=0;i<values.size();i++)
		{
			if(i == 0)
			{
				high = values.get(0);
				index = 0;
			}
			else
			{
				if(high < values.get(i).floatValue())
				{
					high = values.get(i).floatValue();
					index = i;
				}
			}
		}
		if(high>-1)
			return index;
		else
			return -1;
	}
	
	public boolean isFoundinRule(String symbol, String NTSymbol)
	{
		Vector<Grammar> list = this.getRules(NTSymbol);
		for(int i=0;i<list.size();i++)
			if(list.get(i).isFound(symbol))
			{
				//System.out.println(symbol + " is found in " + NTSymbol);
				return true;
			}
		
		for(int i=0;i<list.size();i++)
		{
			Vector<String> annotList = list.get(i).getAnnotations();
			for(int a=0;a<annotList.size();a++)
			{
				if(annotList.get(a).charAt(0) == '!')
				{
					String temp = annotList.get(a);
					temp = temp.substring(1);
					if(recurseIsFoundInRule(symbol, temp, NTSymbol))
					{
						//System.out.println(symbol + " is found in " + NTSymbol);
						return true;
					}
				}
			}
		}
		return false;
	}
	
	public boolean recurseIsFoundInRule(String symbol, String NTSymbol, String start)
	{
		if(!start.equals(NTSymbol))
		{
			return false;
		}
		else
		{
			Vector<Grammar> list = this.getRules(NTSymbol);
			for(int i=0;i<list.size();i++)
				if(list.get(i).isFound(symbol))
					return true;
			
			for(int i=0;i<list.size();i++)
			{
				Vector<String> annotList = list.get(i).getAnnotations();
				for(int a=0;a<annotList.size();a++)
				{
					if(annotList.get(a).charAt(0) == '!')
					{
						String temp = annotList.get(a);
						temp = temp.substring(1);
						if(recurseIsFoundInRule(symbol,temp, start))
							return true;
					}
				}
			}
			return false;
		}
	}
}